package com.xh3140.xwidget.toast;


import android.content.Context;
import android.content.res.Resources;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;

import androidx.annotation.CheckResult;
import androidx.annotation.ColorInt;
import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.AppCompatImageView;
import androidx.appcompat.widget.AppCompatTextView;
import androidx.appcompat.widget.LinearLayoutCompat;
import androidx.core.content.res.ResourcesCompat;

import java.lang.ref.WeakReference;

@SuppressWarnings("unused")
public class Toast extends android.widget.Toast {
  private static WeakReference<Toast> INSTANCE;

  private final LinearLayoutCompat mRootView;
  private final AppCompatImageView mIconView;
  private final AppCompatTextView mMessageView;

  private Toast(@NonNull Context context) {
    super(context);
    mRootView = createRootView(context);
    mIconView = createIconView(context);
    mMessageView = createMessageView(context);
    mRootView.addView(mIconView);
    mRootView.addView(mMessageView);
  }

  private static int dp2px(Context context, int dp) {
    return (int) (dp * context.getResources().getDisplayMetrics().density + 0.5f);
  }

  private static LinearLayoutCompat createRootView(Context context) {
    final LinearLayoutCompat rootView = new LinearLayoutCompat(context);
    final ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
    rootView.setLayoutParams(layoutParams);
    final int padding4 = dp2px(context, 4);
    final int padding8 = dp2px(context, 8);
    rootView.setPaddingRelative(padding8, padding4, padding8, padding4);
    rootView.setOrientation(LinearLayoutCompat.HORIZONTAL);
    return rootView;
  }

  private static AppCompatImageView createIconView(Context context) {
    final AppCompatImageView iconView = new AppCompatImageView(context);
    final int size = dp2px(context, 24);
    final LinearLayoutCompat.LayoutParams layoutParams = new LinearLayoutCompat.LayoutParams(size, size);
    layoutParams.gravity = Gravity.CENTER_VERTICAL;
    iconView.setLayoutParams(layoutParams);
    return iconView;
  }

  @NonNull
  private static AppCompatTextView createMessageView(Context context) {
    final AppCompatTextView messageView = new AppCompatTextView(context);
    final LinearLayoutCompat.LayoutParams layoutParams = new LinearLayoutCompat.LayoutParams(LinearLayoutCompat.LayoutParams.WRAP_CONTENT, LinearLayoutCompat.LayoutParams.WRAP_CONTENT);
    layoutParams.gravity = Gravity.CENTER_VERTICAL;
    messageView.setLayoutParams(layoutParams);
    final int padding = dp2px(context, 8);
    messageView.setPaddingRelative(padding, padding, padding, padding);
    messageView.setGravity(Gravity.CENTER);
    messageView.setTypeface(Typeface.create("sans-serif-condensed", Typeface.NORMAL));
    return messageView;
  }

  //====================================================================================================================================================
  @CheckResult
  public static Toast normal(@NonNull Context context, @NonNull String message) {
    return normal(context, message, Toast.LENGTH_SHORT, true);
  }

  @CheckResult
  public static Toast normal(@NonNull Context context, @NonNull String message, boolean withIcon) {
    return normal(context, message, Toast.LENGTH_SHORT, withIcon);
  }

  @CheckResult
  public static Toast normal(@NonNull Context context, @NonNull String message, int duration) {
    return normal(context, message, duration, true);
  }

  @CheckResult
  public static Toast normal(@NonNull Context context, @NonNull String message, int duration, boolean withIcon) {
    return custom(context, message, withIcon ? Style.NORMAL.icon : 0, Style.NORMAL.textColor, Style.NORMAL.backgroundColor, duration);
  }

  //====================================================================================================================================================
  @CheckResult
  public static Toast info(@NonNull Context context, @NonNull String message) {
    return info(context, message, Toast.LENGTH_SHORT, true);
  }

  @CheckResult
  public static Toast info(@NonNull Context context, @NonNull String message, boolean withIcon) {
    return info(context, message, Toast.LENGTH_SHORT, withIcon);
  }

  @CheckResult
  public static Toast info(@NonNull Context context, @NonNull String message, int duration) {
    return info(context, message, duration, true);
  }

  @CheckResult
  public static Toast info(@NonNull Context context, @NonNull String message, int duration, boolean withIcon) {
    return custom(context, message, withIcon ? Style.INFO.icon : 0, Style.INFO.textColor, Style.INFO.backgroundColor, duration);
  }

  //====================================================================================================================================================
  @CheckResult
  public static Toast success(@NonNull Context context, @NonNull String message) {
    return success(context, message, Toast.LENGTH_SHORT, true);
  }

  @CheckResult
  public static Toast success(@NonNull Context context, @NonNull String message, boolean withIcon) {
    return success(context, message, Toast.LENGTH_SHORT, withIcon);
  }

  @CheckResult
  public static Toast success(@NonNull Context context, @NonNull String message, int duration) {
    return success(context, message, duration, true);
  }

  @CheckResult
  public static Toast success(@NonNull Context context, @NonNull String message, int duration, boolean withIcon) {
    return custom(context, message, withIcon ? Style.SUCCESS.icon : 0, Style.SUCCESS.textColor, Style.SUCCESS.backgroundColor, duration);
  }

  //====================================================================================================================================================
  @CheckResult
  public static Toast warning(@NonNull Context context, @NonNull String message) {
    return warning(context, message, Toast.LENGTH_SHORT, true);
  }

  @CheckResult
  public static Toast warning(@NonNull Context context, @NonNull String message, boolean withIcon) {
    return warning(context, message, Toast.LENGTH_SHORT, withIcon);
  }

  @CheckResult
  public static Toast warning(@NonNull Context context, @NonNull String message, int duration) {
    return warning(context, message, duration, true);
  }

  @CheckResult
  public static Toast warning(@NonNull Context context, @NonNull String message, int duration, boolean withIcon) {
    return custom(context, message, withIcon ? Style.WARNING.icon : 0, Style.WARNING.textColor, Style.WARNING.backgroundColor, duration);
  }

  //====================================================================================================================================================
  @CheckResult
  public static Toast error(@NonNull Context context, @NonNull String message) {
    return error(context, message, Toast.LENGTH_SHORT, true);
  }

  @CheckResult
  public static Toast error(@NonNull Context context, @NonNull String message, boolean withIcon) {
    return error(context, message, Toast.LENGTH_SHORT, withIcon);
  }

  @CheckResult
  public static Toast error(@NonNull Context context, @NonNull String message, int duration) {
    return error(context, message, duration, true);
  }

  @CheckResult
  public static Toast error(@NonNull Context context, @NonNull String message, int duration, boolean withIcon) {
    return custom(context, message, withIcon ? Style.ERROR.icon : 0, Style.ERROR.textColor, Style.ERROR.backgroundColor, duration);
  }

  //====================================================================================================================================================
  @CheckResult
  public static Toast custom(@NonNull Context context, @NonNull String message, @DrawableRes int iconRes, @ColorInt int textColor, @ColorInt int backgroundColor) {
    return custom(context, message, iconRes, textColor, backgroundColor, Toast.LENGTH_SHORT);
  }

  @CheckResult
  public static Toast custom(@NonNull Context context, @NonNull String message, @Nullable Drawable icon, @ColorInt int textColor, @ColorInt int backgroundColor) {
    return custom(context, message, icon, textColor, backgroundColor, Toast.LENGTH_SHORT);
  }

  @CheckResult
  public static Toast custom(@NonNull Context context, @NonNull String message, @DrawableRes int iconRes, @ColorInt int textColor, @ColorInt int backgroundColor, int duration) {
    try {
      final Drawable icon = ResourcesCompat.getDrawable(context.getResources(), iconRes, context.getTheme());
      return custom(context, message, icon, textColor, backgroundColor, duration);
    } catch (Resources.NotFoundException e) {
      return custom(context, message, null, textColor, backgroundColor, duration);
    }
  }

  @CheckResult
  public static Toast custom(@NonNull Context context, @NonNull String message, @Nullable Drawable icon, @ColorInt int textColor, @ColorInt int backgroundColor, int duration) {
    if (INSTANCE != null) {
      final Toast toast = INSTANCE.get();
      if (toast != null) {
        toast.cancel();
      }
    }
    final Toast toast = new Toast(context);
    final GradientDrawable drawable = new GradientDrawable();
    drawable.setCornerRadius(dp2px(context, 5));
    drawable.setColor(backgroundColor);
    toast.mRootView.setBackground(drawable);
    if (icon == null) {
      toast.mIconView.setVisibility(View.GONE);
    } else {
      toast.mIconView.setImageDrawable(icon);
    }
    toast.mMessageView.setText(message);
    toast.mMessageView.setTextColor(textColor);
    toast.setView(toast.mRootView);
    toast.setDuration(duration);
    INSTANCE = new WeakReference<>(toast);
    return toast;
  }


  @NonNull
  public LinearLayoutCompat getRootView() {
    return mRootView;
  }

  @NonNull
  public AppCompatImageView getIconView() {
    return mIconView;
  }

  @NonNull
  public AppCompatTextView getMessageView() {
    return mMessageView;
  }

  private enum Style {
    NORMAL(0, 0xFFFFFFFF, 0xFF535353),
    INFO(R.drawable.ic_toast_info, 0xFFFFFFFF, 0xFF3F51B5),
    SUCCESS(R.drawable.ic_toast_success, 0xFFFFFFFF, 0xFF388E3C),
    WARNING(R.drawable.ic_toast_warning, 0xFFFFFFFF, 0xFFFFA900),
    ERROR(R.drawable.ic_toast_error, 0xFFFFFFFF, 0xFFFD4C5B);

    @DrawableRes
    public final int icon;

    @ColorInt
    public final int textColor;

    @ColorInt
    public final int backgroundColor;

    Style(@DrawableRes int icon, @ColorInt int textColor, @ColorInt int backgroundColor) {
      this.icon = icon;
      this.textColor = textColor;
      this.backgroundColor = backgroundColor;
    }
  }
}
